package main

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"
	"math"
	"strings"
)

const (
	idLength      = 6
	dataDirectory = "data"
)

// Widget 表示仪表板上的一个部件
type Widget struct {
	ID      string `json:"id"`
	X       int    `json:"x"`
	Y       int    `json:"y"`
	Width   int    `json:"width"`
	Height  int    `json:"height"`
	Content string `json:"content"`
	Type    string `json:"type"`
}

var (
	widgets     []Widget
	widgetsLock sync.Mutex
	currentID   string
)

// 可用的部件类型及其默认内容
var widgetTypes = map[string]string{
	"text":    `<div class="text-widget"><h3>文本部件</h3><p>这是文本部件的内容</p></div>`,
	"button":  `<div class="button-widget"><h3>按钮部件</h3><button class="widget-btn">点击我</button></div>`,
	"switch":  `<div class="switch-widget"><h3>开关部件</h3><label class="switch"><input type="checkbox"><span class="slider"></span></label></div>`,
	"image":   `<div class="image-widget"><h3>图片部件</h3><img src="https://via.placeholder.com/100" alt="示例图片"></div>`,
	"chart":   `<div class="chart-widget"><h3>图表部件</h3><div class="chart-placeholder">图表将在这里显示</div></div>`,
}

func inferWidgetType(content string) string {
	if strings.Contains(content, "text-widget") {
		return "text"
	} else if strings.Contains(content, "button-widget") {
		return "button"
	} else if strings.Contains(content, "switch-widget") {
		return "switch"
	} else if strings.Contains(content, "image-widget") {
		return "image"
	} else if strings.Contains(content, "chart-widget") {
		return "chart"
	}
	return "unknown"
}

func main() {
	// 创建data目录
	if err := os.MkdirAll(dataDirectory, 0755); err != nil {
		panic(fmt.Sprintf("无法创建data目录: %v", err))
	}

	r := gin.Default()
	
	// 加载静态文件
	r.Static("/static", "./static")
	
	// 设置模板目录
	r.LoadHTMLGlob("templates/*")
	
	// 主页路由 - 处理ID参数
	r.GET("/", func(c *gin.Context) {
		id := c.Query("id")
		if id == "" {
			// 生成新ID并重定向
			newID := generateUniqueID()
			c.Redirect(http.StatusFound, "/?id="+newID)
			return
		}

		// 验证ID格式
		if len(id) != idLength || !isAlphanumeric(id) {
			c.String(http.StatusBadRequest, "无效的ID格式")
			return
		}

		currentID = id
		layoutFile := getLayoutFilePath(id)

		// 加载布局
		if err := loadLayout(layoutFile); err != nil {
			// 如果是新ID，创建默认布局
			widgets = createDefaultLayout()
			if err := saveLayout(layoutFile); err != nil {
				c.String(http.StatusInternalServerError, "无法创建新布局")
				return
			}
		}

		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "仪表板 - " + id,
			"id":    id,
		})
	})
	
	// 获取所有部件
	r.GET("/api/widgets", func(c *gin.Context) {
		widgetsLock.Lock()
		defer widgetsLock.Unlock()
		
		// 确保所有字段都有值
		for i := range widgets {
			if widgets[i].ID == "" {
				widgets[i].ID = "widget-" + generateRandomString(8)
			}
			if widgets[i].Type == "" {
				widgets[i].Type = inferWidgetType(widgets[i].Content)
			}
		}
		
		c.JSON(http.StatusOK, gin.H{
			"widgets": widgets,
		})
	})

	// 保存布局
	r.POST("/api/save-layout", func(c *gin.Context) {
		var newWidgets []Widget
		if err := c.ShouldBindJSON(&newWidgets); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		widgetsLock.Lock()
		widgets = newWidgets
		widgetsLock.Unlock()
		
		if err := saveLayout(getLayoutFilePath(currentID)); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		
		c.JSON(http.StatusOK, gin.H{"status": "布局保存成功"})
	})
	
	// 添加新部件
	r.POST("/api/add-widget", func(c *gin.Context) {
		var request struct {
			Type string `json:"type"`
			X    int    `json:"x"`
			Y    int    `json:"y"`
		}
		if err := c.ShouldBindJSON(&request); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		content, exists := widgetTypes[request.Type]
		if !exists {
			c.JSON(http.StatusBadRequest, gin.H{"error": "无效的部件类型"})
			return
		}
		
		widget := Widget{
			ID:      "widget-" + generateRandomString(8),
			X:       request.X,
			Y:       request.Y,
			Width:   2,  // 修改默认宽度为2
			Height:  2,  // 修改默认高度为2
			Content: content,
			Type:    request.Type,
		}
		
		widgetsLock.Lock()
		widgets = append(widgets, widget)
		widgetsLock.Unlock()
		
		if err := saveLayout(getLayoutFilePath(currentID)); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		
		c.JSON(http.StatusOK, gin.H{
			"status": "部件添加成功",
			"widget": widget,
		})
	})
	
	// 删除部件
	r.POST("/api/remove-widget", func(c *gin.Context) {
		var request struct {
			ID string `json:"id"`
		}
		if err := c.ShouldBindJSON(&request); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		widgetsLock.Lock()
		newWidgets := make([]Widget, 0, len(widgets))
		for _, w := range widgets {
			if w.ID != request.ID {
				newWidgets = append(newWidgets, w)
			}
		}
		widgets = newWidgets
		widgetsLock.Unlock()
		
		if err := saveLayout(getLayoutFilePath(currentID)); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		
		c.JSON(http.StatusOK, gin.H{"status": "部件删除成功"})
	})
	
	// 启动服务器
	r.Run(":8088")
}

// 生成唯一ID (6位数字字母)
func generateUniqueID() string {
	for {
		id := generateRandomString(idLength)
		if !layoutExists(id) {
			return id
		}
	}
}

// 检查布局文件是否存在
func layoutExists(id string) bool {
	_, err := os.Stat(getLayoutFilePath(id))
	return !os.IsNotExist(err)
}

// 获取布局文件路径
func getLayoutFilePath(id string) string {
	return filepath.Join(dataDirectory, id+".json")
}

// 生成随机字符串
func generateRandomString(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := range b {
		b[i] = charset[rand.Intn(len(charset))]
	}
	return string(b)
}

// 检查字符串是否只包含字母数字
func isAlphanumeric(s string) bool {
	for _, r := range s {
		if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9')) {
			return false
		}
	}
	return true
}

// 创建默认布局
func createDefaultLayout() []Widget {
	return []Widget{
		{
			ID:      "widget-" + generateRandomString(8),
			X:       0,
			Y:       0,
			Width:   4,
			Height:  2,
			Content: widgetTypes["text"],
			Type:    "text",
		},
		{
			ID:      "widget-" + generateRandomString(8),
			X:       4,
			Y:       0,
			Width:   4,
			Height:  2,
			Content: widgetTypes["button"],
			Type:    "button",
		},
	}
}

// 加载布局
func loadLayout(filePath string) error {
	data, err := os.ReadFile(filePath)
	if err != nil {
		return err
	}
	
	widgetsLock.Lock()
	defer widgetsLock.Unlock()
	return json.Unmarshal(data, &widgets)
}

// 保存布局
func saveLayout(filePath string) error {
	widgetsLock.Lock()
	defer widgetsLock.Unlock()
	
	// 确保所有坐标和尺寸是整数
	for i := range widgets {
		widgets[i].X = int(math.Round(float64(widgets[i].X)))
		widgets[i].Y = int(math.Round(float64(widgets[i].Y)))
		widgets[i].Width = int(math.Max(1, math.Round(float64(widgets[i].Width))))
		widgets[i].Height = int(math.Max(1, math.Round(float64(widgets[i].Height))))
	}
	
	data, err := json.MarshalIndent(widgets, "", "  ")
	if err != nil {
		return err
	}
	
	return os.WriteFile(filePath, data, 0644)
}

func init() {
	rand.Seed(time.Now().UnixNano())
}